﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web;
using Altairis.Web.Management.Configuration;

namespace Altairis.Web.Management {

    [Obsolete("This class is obsolete. Use URL routing instead when possible.")]
    public class UrlRewritingModule : IHttpModule {
        private const string RewriteMarkKey = "Altairis.Web.Management.UrlRewritingModule.RewriteMark";

        private ManagementSection config;
        private IEnumerable<UrlRewritingRuleElement> rules;

        public void Dispose() { }

        public void Init(HttpApplication context) {
            // Load configuration
            this.config = ManagementSection.GetCurrentOrDefault();

            // Check if URL rewriting is enabled and that there are some rules defined
            if (this.config == null) throw new NullReferenceException();
            if (!this.config.UrlRewriting.Enabled || this.config.UrlRewriting.Rules == null || this.config.UrlRewriting.Rules.Count == 0) return;

            // Convert rules to LINQ-compatible format
            this.rules = config.UrlRewriting.Rules.Cast<UrlRewritingRuleElement>();

            // Hook up event for phase 1 (rewriting)
            if (this.config.UrlRewriting.Stage == UrlRewritingStage.BeginRequest) {
                context.BeginRequest += new EventHandler(Phase1Handler);
            }
            else {
                context.PostAuthorizeRequest += new EventHandler(Phase1Handler);
            }

            // Hook up event for phase 2 (rewriting back for proper function of Web Forms)
            context.PreRequestHandlerExecute += new EventHandler(Phase2Handler);
        }

        private void Phase1Handler(object sender, EventArgs e) {
            var app = sender as HttpApplication;

            // Skip infrastructure requests
            if (this.config.UrlRewriting.ExcludeSystemUrls && app.Request.IsInfrastructureRequest()) return;

            // Find first matching rule
            var matchingRule = this.rules.FirstOrDefault(x => Regex.IsMatch(app.Request.AppRelativeCurrentExecutionFilePath, x.From, x.CaseSensitive ? RegexOptions.None : RegexOptions.IgnoreCase));
            if (matchingRule == null) return; // no matching rule found

            // Create internal URL
            var options = matchingRule.CaseSensitive ? RegexOptions.None : RegexOptions.IgnoreCase;
            var internalUrl = Regex.Replace(app.Request.AppRelativeCurrentExecutionFilePath, matchingRule.From, matchingRule.To, options);

            // Perform required action
            switch (matchingRule.Action) {
                case UrlRewritingAction.Rewrite:            // Rewrite
                    // Append context items
                    foreach (UrlRewritingMapElement map in matchingRule.MapContextItems) {
                        app.Context.Items[map.Key] = Regex.Replace(app.Request.AppRelativeCurrentExecutionFilePath, matchingRule.From, map.Value, options);
                    }

                    // Perform rewriting
                    app.Context.Items[RewriteMarkKey] = app.Request.RawUrl;
                    app.Context.RewritePath(internalUrl, false);
                    break;
                case UrlRewritingAction.Redirect:           // Temporary redirect
                    app.Response.Redirect(internalUrl + app.Request.Url.Query);
                    break;
                case UrlRewritingAction.PermanentRedirect:  // Permanent redirect
                    app.Response.RedirectPermanent(internalUrl + app.Request.Url.Query);
                    break;
                default:                                    // None or unknown
                    break;
            }
        }

        private void Phase2Handler(object sender, EventArgs e) {
            var app = sender as HttpApplication;

            // Check if URL was rewritten
            string originalUrl = app.Context.Items[RewriteMarkKey] as string;
            if (string.IsNullOrEmpty(originalUrl)) return;
            app.Context.RewritePath(originalUrl, false);

            // Rewrite back on handler level
            var page = app.Context.Handler as System.Web.UI.Page;
            if (page != null) {
                if (originalUrl.IndexOf('?') > -1) originalUrl = originalUrl.Substring(0, originalUrl.IndexOf('?'));
                page.AppRelativeVirtualPath = originalUrl;
                if (originalUrl.EndsWith("/")) {
                    page.AppRelativeTemplateSourceDirectory = originalUrl;
                }
                else {
                    page.AppRelativeTemplateSourceDirectory = VirtualPathUtility.GetDirectory(originalUrl);
                }

            }
        }

    }
}